﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Brain
{
    public class Sprite : ISprite, ITextured, ISpriteFonted, IShadowed, IBaseComponent, IBounded, IEffected, IDisposable
    {
        /// <summary>
        /// TO-DO: Finish writing Dispose method, only
        /// removes the Sprite from the renderer(set Rendering
        /// to SpriteRendering.Invisible)
        /// </summary>
        public void Dispose()
        {
            this.Rendering = SpriteRendering.Invisible;
        }

        public bool ShouldSerialize { get; set; }

        public Effect Effect { get; set; }

        public int Shadow { get; set; }

        public Color Color { get; set; }

        public Vector2? Origin { get; set; }

        private Vector2 position;
        public Vector2 Position
        {
            get { return position; }
            set
            {
                position = value;
                boundsRectangle = new Rectangle((int)value.X, (int)value.Y, boundsRectangle.Width, boundsRectangle.Height);
            }
        }

        /// <summary>
        /// This Sprite Bounds
        /// </summary>
        public Rectangle BoundsRectangle
        {
            get { return boundsRectangle; }
            set 
            { 
                boundsRectangle = value;
                position = new Vector2(value.X, value.Y);
            }
        }
        private Rectangle boundsRectangle;

        /// <summary>
        /// If not null, will render the Sprite's rectangle
        /// </summary>
        public Color? BoundsRectangleColor { get; set; }

        /// <summary>
        /// If it should update
        /// </summary>
        public bool ShouldUpdate { get; set; }

        /// <summary>
        /// If the Sprite Should draw
        /// </summary>
        public bool ShouldDraw { get; set; }

        public SpriteEffects SpriteEffects { get; set; }


        private string texturePlace;
        /// <summary>
        /// The location of the Sprite's Texture
        /// </summary>
        public string TexturePlace
        {
            get { return texturePlace; }
            set
            {
                texturePlace = value;
                if (!string.IsNullOrEmpty(value))
                {
                    Texture = Engine.Instance.ContentManager.Load<Texture2D>(value);
                }
            }
        }
        public Rectangle? SourceRectangle { get; set; }

        public float RotationAngle { get; set; }

        /// <summary>
        /// The Texture this sprite will render
        /// </summary>
        public Texture2D Texture
        {
            get { return texture; }
            set
            {
                texture = value;
                if (value != null)
                {
                    boundsRectangle = new Rectangle(
                        (int)position.X,
                        (int)position.Y,
                        value.Width,
                        value.Height);
                }
            }
        }
        private Texture2D texture;

        private SpritePhysics physics;
        public SpritePhysics Physics
        {
            get
            {
                return physics;
            }
            set
            {
                SpritePhysics lastState = physics;
                physics = value;
                if (Engine.Instance.Physics2DManager != null)
                {
                    Engine.Instance.Physics2DManager.ChangedState(this, lastState);
                }
            }
        }

        /// <summary>
        /// A Sprite conected to this sprite as a son
        /// </summary>
        public Sprite Son
        {
            get { return son; }
            set
            {
                son = value;
                relativeSonPosition = son.Position;
                relativeSonRotationAngle = son.RotationAngle;
            }
        }
        private Sprite son;
        private Vector2? relativeSonPosition;
        private float? relativeSonRotationAngle;

        public SpriteFont SpriteFont { get; set; }

        private string spriteFontPlace;
        /// <summary>
        /// The location of the Sprite's Texture
        /// </summary>
        public string SpriteFontPlace
        {
            get { return spriteFontPlace; }
            set
            {
                spriteFontPlace = value;
                if (!string.IsNullOrEmpty(value))
                {
                    SpriteFont = Engine.Instance.ContentManager.Load<SpriteFont>(value);
                }
            }
        }
        public string Name { get; set; }

        public string Text { get; set; }

        private SpriteRendering rendering;
        public SpriteRendering Rendering
        {
            get { return rendering; }
            set 
            {
                if (Engine.Instance.RenderManager2D != null)
                {
                    if (value == SpriteRendering.Invisible &&
                        value != rendering)
                    {
                        if (Engine.Instance.Editor == null)
                        {
                            Engine.Instance.RenderManager2D.RemoveSprite(this);
                        }
                    }
                    if (value == SpriteRendering.Rendered && value != rendering  ||
                        value == SpriteRendering.EditorVisible && Engine.Instance.Editor != null)
                    {
                        Engine.Instance.RenderManager2D.SubmitSprite(this);
                    }
                    rendering = value;

                    
                }
            }
        }

        public void Draw()
        {
        }

        public Sprite()
        {
            Color = Color.White;
            this.BoundsRectangle = new Rectangle(0, 0, 32, 32);
            ShouldSerialize = true;
        }

        public void UpdateBoundsRectangle()
        {
            Rectangle? TexRectangle = null;

            if (Texture != null)
            {
                TexRectangle = RectangleUtil.GetTextureRectangle(Texture, this.Position);
            }
            Rectangle? TextRectangle = null;
            if (!string.IsNullOrEmpty(Text) && SpriteFont != null)
            {
                Vector2 measure = SpriteFont.MeasureString(this.Text);

                TextRectangle = RectangleUtil.GetStringRectangle(Text, SpriteFont, this.Position);
            }

            bool TextRectangleNull = TextRectangle == null;
            bool TexRectangleNull = TexRectangle == null;

            if (TextRectangleNull &&
                !TexRectangleNull)
            {
                BoundsRectangle = TexRectangle.Value;
            }
            else if (!TextRectangleNull &&
                TexRectangleNull)
            {
                BoundsRectangle = TextRectangle.Value;
            }
            else if (TextRectangleNull &&
                TexRectangleNull)
            {
                // do nothing
            }
            else
            {
                Rectangle TextR = TextRectangle.Value;
                Rectangle TexR = TexRectangle.Value;
                BoundsRectangle = RectangleUtil.Add(TextR, TextR);
            }
        }

        public void Update()
        {
            if (Son != null)
            {
                Son.Position = this.Position;
                Son.RotationAngle = this.RotationAngle + relativeSonRotationAngle.Value;
            }

            if (Physics != SpritePhysics.NoPhysics)
            {
                if (Engine.Instance.Physics2DManager != null)
                {
                    BoundsRectangle = Engine.Instance.Physics2DManager.GetRectangle(this);
                }
            }
            else
            {

            }
        }

        public void SerializeData(SerializationData parentData, int index)
        {
            parentData.AddData("Sprite.Name", this.Name, index);
            parentData.AddData("Sprite.BoundsRectangle", this.BoundsRectangle, index);
            parentData.AddData("Sprite.Color", this.Color, index);
            parentData.AddData("Sprite.Physics", (int)this.physics, index);
            parentData.AddData("Sprite.RotationAngle", this.RotationAngle, index);
            parentData.AddData("Sprite.Shadow", this.Shadow, index);
            parentData.AddData("Sprite.ShouldDraw", this.ShouldDraw, index);
            parentData.AddData("Sprite.ShouldUpdate", this.ShouldUpdate, index);
            parentData.AddData("Sprite.SpriteEffects", (int)this.SpriteEffects, index);
            parentData.AddData("Sprite.Text", this.Text, index);
            parentData.AddData("Sprite.Rendering", (int)this.Rendering, index);
            if (SourceRectangle != null)
            {
                parentData.AddData("Sprite.SourceRectangle", this.SourceRectangle, index);
            }
            if (!string.IsNullOrEmpty(texturePlace))
            {
                parentData.AddData("Sprite.TexturePlace", this.texturePlace, index);
            }
            if (!string.IsNullOrEmpty(spriteFontPlace))
            {
                parentData.AddData("Sprite.SpriteFontPlace", this.SpriteFontPlace, index);
            }
        }

        public void DeserializeData(SerializationData parentData, int index)
        {
            this.Name = parentData.GetData<string>("Sprite.Name", index);
            this.BoundsRectangle = parentData.GetData<Rectangle>("Sprite.BoundsRectangle", index);
            this.Color = parentData.GetData<Color>("Sprite.Color", index);
            this.Physics = (SpritePhysics)parentData.GetData<int>("Sprite.Physics", index);
            this.RotationAngle = parentData.GetData<float>("Sprite.RotationAngle", index);
            this.Shadow = parentData.GetData<int>("Sprite.Shadow", index);
            this.ShouldDraw = parentData.GetData<bool>("Sprite.ShouldDraw", index);
            this.ShouldUpdate = parentData.GetData<bool>("Sprite.ShouldUpdate", index);
            this.SpriteEffects = (SpriteEffects)parentData.GetData<int>("Sprite.SpriteEffects", index);
            this.Text = parentData.GetData<string>("Sprite.Text", index);
            this.Rendering = (SpriteRendering)parentData.GetData<int>("Sprite.Rendering", index);

            this.SourceRectangle = parentData.GetData<Rectangle?>("Sprite.SourceRectangle", index);
            this.TexturePlace = parentData.GetData<string>("Sprite.TexturePlace", index);
            this.SpriteFontPlace = parentData.GetData<string>("Sprite.SpriteFontPlace", index);
        }




    }
}
